#pragma  once
#include "mini_sr.h"


using namespace std;

namespace mini_sr
{
    class InputStream
    {
        string m_buf;
        unsigned int m_cur;
    public:
        InputStream()
            :m_cur(0)
        {
        }
        InputStream(string& buf)
            :m_buf(buf)
            ,m_cur(0)
        {

        }
        InputStream& operator &(bool& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = m_buf[m_cur++] > 0 ? true : false;

            LOG_VALUE(InputStream& operator & (bool&) ,v);
                    
            return *this;
        }
        InputStream& operator &(char& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = m_buf[m_cur++];

            LOG_VALUE(InputStream& operator & (char&) ,v);
                    
            return *this;
        }
        InputStream& operator &(unsigned char& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = m_buf[m_cur++];

            LOG_VALUE(InputStream& operator & (unsigned char&) ,v);
                                
            return *this;
        }
        InputStream& operator &(short& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                ;

            LOG_VALUE(InputStream& operator & (short&) ,v);
                    
            return *this;
        }
        InputStream& operator &(unsigned short& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                ;            

            LOG_VALUE(InputStream& operator & (unsigned short&) ,v);
                    
            return *this;
        }
        InputStream& operator &(int& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                | ((unsigned char)m_buf[m_cur++]<<16)
                | ((unsigned char)m_buf[m_cur++]<<24)
                ;

            LOG_VALUE(InputStream& operator & (int&) ,v);
        
            return *this;
        }
        InputStream& operator &(unsigned int& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                | ((unsigned char)m_buf[m_cur++]<<16)
                | ((unsigned char)m_buf[m_cur++]<<24)
                ;

            LOG_VALUE(InputStream& operator & (unsigned int&) ,v);
                    
            return *this;
        }
        InputStream& operator &(long& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                | ((unsigned char)m_buf[m_cur++]<<16)
                | ((unsigned char)m_buf[m_cur++]<<24)
                ;

            LOG_VALUE(InputStream& operator & (long&) ,v);
                    
            return *this;
        }
        InputStream& operator &(unsigned long& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                | ((unsigned char)m_buf[m_cur++]<<16)
                | ((unsigned char)m_buf[m_cur++]<<24)
                ;

            LOG_VALUE(InputStream& operator & (unsigned long&) ,v);
                    
            return *this;
        }

        InputStream& operator &(long long& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                | ((unsigned char)m_buf[m_cur++]<<16)
                | ((unsigned char)m_buf[m_cur++]<<24)
                | ((long long)(unsigned char)m_buf[m_cur++]<<32)
                | ((long long)(unsigned char)m_buf[m_cur++]<<40)
                | ((long long)(unsigned char)m_buf[m_cur++]<<48)
                | ((long long)(unsigned char)m_buf[m_cur++]<<56)
                ;

            LOG_VALUE(InputStream& operator & (long long&) ,v);
                    
            return *this;
        }
        InputStream& operator &(unsigned long long& v)
        {
            ASSERT(m_cur < m_buf.size());
            v = (unsigned char)m_buf[m_cur++] 
                | ((unsigned char)m_buf[m_cur++]<<8)
                | ((unsigned char)m_buf[m_cur++]<<16)
                | ((unsigned char)m_buf[m_cur++]<<24)
                | ((unsigned long long)(unsigned char)m_buf[m_cur++]<<32)
                | ((unsigned long long)(unsigned char)m_buf[m_cur++]<<40)
                | ((unsigned long long)(unsigned char)m_buf[m_cur++]<<48)
                | ((unsigned long long)(unsigned char)m_buf[m_cur++]<<56)
                ;

            LOG_VALUE(InputStream& operator & (unsigned long long&) ,v);
                    
            return *this;
        }
        InputStream& operator &(float& v)
        {
            ASSERT(m_cur < m_buf.size());
            char* p = (char*)&v;
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];

            LOG_VALUE(InputStream& operator & (float&),v);
                   
            return *this;
        }
        InputStream& operator &(double& v)
        {
            ASSERT(m_cur < m_buf.size());
            char* p = (char*)&v;
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];
            *p++ = m_buf[m_cur++];

            LOG_VALUE(InputStream& operator & (double&) ,v);
                    
            return *this;
        }
        InputStream& operator &(string& v)
        {
            ASSERT(m_cur < m_buf.size());
            v.clear();
            unsigned int l = 0;
            operator & (l);
            for(unsigned int i = 0;i< l;i++)
            {
                v.push_back(m_buf[m_cur++]);
            }

            LOG_VALUE(InputStream& operator & (string&) ,v);
        
            return *this;
        }
        template<class T>
        InputStream& operator & (T& v)
        {
            //LOG_VALUE(InputStream& operator & (T& v) T,typeid(v).name());
            
            unsigned char sr_version = 0;
            unsigned short len = 0;
            operator & (sr_version);
            operator & (len);
            unsigned short bsize = (unsigned short)m_cur;
            v.serialization(*this,sr_version);
            unsigned short rlen = m_cur - bsize;
            LOG("len = "<<len<<",rlen="<<rlen);
            ASSERT(len == rlen);
            return *this;
        }
        template<class T>
        InputStream& operator & (std::vector<T>& list)
        {
            list.clear();
            unsigned int l = 0;
            operator & (l);
            while(l > 0)
            {
                T t;
                operator & (t);
                list.push_back(t);
                l--;
            }
            return *this;
        }
        template<typename K,typename V>
        InputStream& operator & (std::map<K,V>& l_map)
        {
            l_map.clear();
            unsigned int l = 0;
            operator & (l);
            while(l > 0)
            {
                K k;
                V v;
                operator & (k);
                operator & (v);
                l_map[k] = v;
                l--;
            }
            return *this;
        }
        template<typename K,typename V>
        InputStream& operator & (stdext::hash_map<K,V>& l_map)
        {
            l_map.clear();
            unsigned int l = 0;
            operator & (l);
            while(l > 0)
            {
                K k;
                V v;
                operator & (k);
                operator & (v);
                l_map[k] = v;
                l--;
            }
            return *this;
        }
        string& decode(string& in)
        {
            unsigned int l = in.size();
            m_buf.clear();
            m_cur = 0;

            for(unsigned int i = 0;m_cur < l;)
            {
                string::value_type c = in[m_cur];
                if(c == ESCAPE_CHAR )
                {
                    if(m_cur < l)
                    {
                        string::value_type nc = in[m_cur + 1];
                        switch(nc)
                        {
                        case ESCAPE_ESCAPE:
                            {
                                m_buf.push_back(ESCAPE_CHAR);
                                m_cur += 2;
                            }
                            break;
                        case ESCAPE_NULL:
                            {
                                m_buf.push_back(0);
                                m_cur += 2;
                            }
                            break;
                        case ESCAPE_CONTINUE_ESCAPE:
                            {
                                int nlen = (unsigned char)in[m_cur+2];
                                ASSERT(nlen);
                                while(nlen --)
                                {
                                    m_buf.push_back(ESCAPE_CHAR);
                                }                            
                                m_cur += 3;
                            }
                            break;
                        case ESCAPE_CONTINUE_NULL:
                            {
                                int nlen = (unsigned char)in[m_cur+2];
                                ASSERT(nlen);
                                while(nlen --)
                                {
                                    m_buf.push_back(0);
                                }
                                m_cur += 3;
                            }
                            break;
                        }

                    }
                    else
                    {
                        ASSERT(FALSE);
                    }
                }
                else
                {
                    m_buf.push_back(c);
                    m_cur ++;
                }
            }
            m_cur = 0;
            return m_buf;
        }
        string fromHex(const string& hex)
        {
            string& data = m_buf;
            data.clear();
            for(string::const_iterator b = hex.begin(),e = hex.end();
                b != e;
                b++)
            {
                unsigned char d = 0;
                char c = *b;
                if(c >= '0' && c <= '9')
                {
                    d |= c - '0';
                }
                else
                {
                    d |= c - 'A'+10;
                }
                b++;
                c = *b;
                if(c >= '0' && c <= '9')
                {
                    d |= (c - '0') << 4;
                }
                else
                {
                    d |= (c - 'A'+10) << 4;
                }
                data.push_back(d);
            }
            return data;
        }
    };
}
